/**
 * Copyright (C) 2010 altuure <altuure [AT] gmail [DOT] com> http://www.altuure.com/projects/yagdao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.altuure.yagdao.grammar;

import com.altuure.yagdao.grammar.YagdaoParser.result_list_return;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.RecognizerSharedState;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import javax.persistence.criteria.*;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

public class JpaTreeSamples {
    @Rule
    public TestName name= new TestName();

    private Map joins;
    private CriteriaBuilder criteriaBuilder;
    private Root from;

    @Test
    public void test0() throws RecognitionException {
        testResultList( "abc",1);
        verify(from).get("abc");
       
    }
    @Test
    public void test1() throws RecognitionException {
        Join join1 = mock(Join.class);
        when(from.join("ttt")).thenReturn(join1);
        testResultList( "abc,ttt.dd,fff",3);
        verify(from).get("abc");
        verify(from).join("ttt");
        verify(join1).get("dd");
        verify(from).get("fff");

    }
    @Test
    public void test2_1() throws RecognitionException {
         Path path = mock(Path.class);
         Expression min_exp = mock(Expression.class);
         when(from.get("id")).thenReturn(path);
         when(criteriaBuilder.min(path)).thenReturn(min_exp);
        
         testResultList( "min(id)",1);
        verify(from).get("id");
        verify(criteriaBuilder).min(path);
        
        
        
      
    }
    @Test
    public void test2() throws RecognitionException {
        Path id_path = mock(Path.class);
        Path id2_path = mock(Path.class);
        Path fff_path = mock(Path.class);
        Path xdd_path = mock(Path.class);
        Expression min_exp = mock(Expression.class);
        Expression max_exp = mock(Expression.class);
        Expression count_exp = mock(Expression.class);
        Expression avg_exp = mock(Expression.class);
       
        when(from.get("id")).thenReturn(id_path);
        when(criteriaBuilder.min(id_path)).thenReturn(min_exp);
        
        when(from.get("id2")).thenReturn(id2_path);
        when(criteriaBuilder.max(id_path)).thenReturn(max_exp);

        when(from.get("fff")).thenReturn(fff_path);
        when(criteriaBuilder.max(id_path)).thenReturn(count_exp);
        
        when(from.get("xdd")).thenReturn(xdd_path);
        when(criteriaBuilder.avg(id_path)).thenReturn(avg_exp);
        
        testResultList( "min(id),max(id2),count(fff),avg(xdd)",4);
        verify(from).get("id");
        
        
    }
    @Test
    public void test3() throws RecognitionException {
        Join id_join = mock(Join.class);
        Path ddd_path = mock(Path.class);
        Expression min_exp = mock(Expression.class);
        when(from.join("id")).thenReturn(id_join);
        when(id_join.get("ddd")).thenReturn(ddd_path);
       
       
        testResultList( "min(id.ddd)",1);
       verify(from).join("id");
       verify(id_join).get("ddd");
       when(criteriaBuilder.min(ddd_path)).thenReturn(min_exp);
    }
    @Test
    public void test4() throws RecognitionException {
        testResultList( "distinct dd",1);
    }
    @Test
    public void test5() throws RecognitionException {
        Join join1 = mock(Join.class);
        when(from.join("ddds")).thenReturn(join1);
        testResultList( "ddds.ddd",1);
        verify(from).join("ddds");
        verify(join1).get("ddd");
    }
    @Before
    public void setup(){
        criteriaBuilder = mock(CriteriaBuilder.class);
        from = mock(Root.class);
        joins = mock(Map.class);
        
        
    }

    /**
     * @param input
     * @param i 
     * @return 
     * @throws RecognitionException
     */
    public List testResultList(String input, int size) throws RecognitionException {
        System.out.println(name.getMethodName()+":begin:"+input);
        ANTLRStringStream stringStream = new ANTLRStringStream(input);
        final YagdaoLexer lexer = new YagdaoLexer(stringStream);
        YagdaoParser parser = new YagdaoParser(new CommonTokenStream(lexer));

        result_list_return result_list = parser.result_list();
        List<String> errors = parser.getErrors();
       
        for (String string : errors) {
            System.err.println(name.getMethodName()+"/ERROR:"+string);
        }
        Assert.assertTrue(errors.isEmpty());
        CommonTree tree = (CommonTree)result_list.getTree();
        System.out.println(input+":");
        System.out.println("\t"+tree.toStringTree()+"\n");
        


        CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
        RecognizerSharedState state = new RecognizerSharedState();
        state.backtracking=0;
        JpaTreeWalker evaluator = new JpaTreeWalker(nodes, state);
        evaluator.init(from, joins, criteriaBuilder);
        List l=evaluator.result_list().list;
        errors = evaluator.getErrors();
        for (String string : errors) {
            System.err.println("ERROR:"+string);
        }
        Assert.assertTrue(evaluator.getErrors().isEmpty());
        System.out.println(name.getMethodName()+":END:"+input);
        assertEquals(size, l.size());
        return l;


     
    }
}
